<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      canvas {
        display: block;
        margin: 0 auto;
      }
      .tip {
        text-align: center;
        line-height: 80px;
      }
    </style>
  </head>
  <body>
    <script>
      let isBlack = true;
      // 创建棋盘
      const canvas = document.createElement("canvas");
      canvas.width = 800;
      canvas.height = 800;
      const tip = document.createElement("div");
      tip.classList.add("tip");
      tip.innerText = `请${isBlack ? "黑棋" : "白棋"}落子`;
      document.body.append(tip);
      document.body.append(canvas);
      const ROUND = 2 * Math.PI;
      let rows = canvas.width / 50;
      const context = canvas.getContext("2d");
      //   context.fillStyle = "#090";
      //   context.fillRect(0, 0, 800, 800);

      //   for (let i = 1; i < rows; i++) {
      //     context.moveTo(50, i * 50);
      //     context.lineTo(750, i * 50);
      //     context.stroke();

      //     context.moveTo(50 * i, 50);
      //     context.lineTo(i * 50, 750);
      //     context.stroke();
      //   }

      const whiteStartColor = "#666";
      const whiteEndColor = "#fff";

      const blackStartColor = "#ccc";
      const blackEndColor = "#000";

      //   context.shadowBlur = 4;
      context.shadowColor = "#333";
      //   context.shadowOffsetX = 4;
      //   context.shadowOffsetY = 4;

      const cs = Array(rows + 1)
        .fill(1)
        .map(() => []);

      // 点击事件
      canvas.addEventListener("click", (e) => {
        if (gameEnd) {
          return alert("游戏已经结束，请刷新");
        }

        if (
          e.offsetX < 25 ||
          e.offsetX > 775 ||
          e.offsetY < 25 ||
          e.offsetY > 775
        ) {
          return;
        }

        let row = Math.floor((e.offsetY + 25) / 50);
        let col = Math.floor((e.offsetX + 25) / 50);

        if (cs[row][col]) {
          tip.innerText = `此处已经落子，请${
            isBlack ? "黑棋" : "白棋"
          }重新落子`;
          return;
        }

        cs[row][col] = isBlack ? "b" : "w";

        // let x = col * 50;
        // let y = row * 50;
        // context.beginPath();
        // context.arc(x, y, 20, 0, ROUND);

        // let gx = isBlack ? x - 10 : x + 10;
        // let gy = isBlack ? y - 10 : y + 10;

        // let g = context.createRadialGradient(gx, gy, 0, gx, gy, 30);
        // g.addColorStop(0, isBlack ? blackStartColor : whiteStartColor);
        // g.addColorStop(1, isBlack ? blackEndColor : whiteEndColor);
        // context.fillStyle = g;
        // context.fill();

        gameEnd = checkWin(row, col);
        if (gameEnd) {
          tip.innerText = `${isBlack ? "黑棋" : "白棋"}胜利！！`;
          return;
        }
        isBlack = !isBlack;
        tip.innerText = `请${isBlack ? "黑棋" : "白棋"}落子`;
      });

      let gameEnd = false;
      function checkWin(row, col) {
        return (
          checkVertical(row, col) ||
          checkHorizontal(row, col) ||
          checkWN2ES(row, col) ||
          checkEN2WS(row, col)
        );
      }

      function checkVertical(row, col) {
        let count = 1;
        let t = 0;
        let up = 1;
        let down = 1;
        let tar = isBlack ? "b" : "w";
        while (t < 10000) {
          t++;
          if (cs[row - up][col] === tar) {
            count++;
          }
          if (cs[row + down][col] === tar) {
            count++;
          }
          if (
            count >= 5 ||
            (cs[row - up][col] !== tar && cs[row + down][col] !== tar)
          ) {
            break;
          }
          up++;
          down++;
        }
        return count >= 5;
      }

      function checkHorizontal(row, col) {
        let count = 1;
        let t = 0;
        let left = 1;
        let right = 1;
        let tar = isBlack ? "b" : "w";
        while (t < 10000) {
          t++;
          if (cs[row][col - left] === tar) {
            count++;
          }
          if (cs[row][col + right] === tar) {
            count++;
          }
          if (
            count >= 5 ||
            (cs[row][col - left] !== tar && cs[row][col + right] !== tar)
          ) {
            break;
          }
          left++;
          right++;
        }
        return count >= 5;
      }

      function checkWN2ES(row, col) {
        let count = 1;
        let t = 0;
        let tl = 1;
        let br = 1;
        let tar = isBlack ? "b" : "w";
        while (t < 10000) {
          t++;
          if (cs[row - tl][col - tl] === tar) {
            count++;
          }
          if (cs[row + br][col + br] === tar) {
            count++;
          }
          if (
            count >= 5 ||
            (cs[row - tl][col - tl] !== tar && cs[row + br][col + br] !== tar)
          ) {
            break;
          }
          tl++;
          br++;
        }
        return count >= 5;
      }

      function checkEN2WS(row, col) {
        let count = 1;
        let t = 0;
        let tr = 1;
        let bl = 1;
        let tar = isBlack ? "b" : "w";
        while (t < 10000) {
          t++;
          if (cs[row - tr][col + tr] === tar) {
            count++;
          }
          if (cs[row + bl][col - bl] === tar) {
            count++;
          }
          if (
            count >= 5 ||
            (cs[row - tr][col + tr] !== tar && cs[row + bl][col - bl] !== tar)
          ) {
            break;
          }
          tr++;
          bl++;
        }
        return count >= 5;
      }

      let curX = 8;
      let curY = 8;
      canvas.addEventListener("mousemove", (e) => {
        if (
          e.offsetX < 25 ||
          e.offsetX > 775 ||
          e.offsetY < 25 ||
          e.offsetY > 775
        ) {
          return;
        }

        curY = Math.floor((e.offsetY + 25) / 50) * 50;
        curX = Math.floor((e.offsetX + 25) / 50) * 50;
      });

      function render() {
        context.clearRect(0, 0, 800, 800);
        // context.shadowBlur = 0;
        // context.shadowOffsetX = 0;
        // context.shadowOffsetY = 0;
        context.setLineDash([]);
        context.strokeStyle = "#000";
        context.fillStyle = "#090";
        context.fillRect(0, 0, 800, 800);

        for (let i = 1; i < rows; i++) {
          context.beginPath();
          context.moveTo(50, i * 50);
          context.lineTo(750, i * 50);
          context.stroke();
          context.closePath();

          context.beginPath();
          context.moveTo(50 * i, 50);
          context.lineTo(i * 50, 750);
          context.stroke();
          context.closePath();
        }

        context.shadowBlur = 4;
        context.shadowOffsetX = 4;
        context.shadowOffsetY = 4;
        cs.forEach((arr, row) => {
          arr.forEach((item, col) => {
            if (item) {
              let x = col * 50;
              let y = row * 50;
              context.beginPath();
              context.arc(x, y, 20, 0, ROUND);
              context.closePath();

              let isBlack = item === "b";
              let gx = isBlack ? x - 10 : x + 10;
              let gy = isBlack ? y - 10 : y + 10;

              let g = context.createRadialGradient(gx, gy, 0, gx, gy, 30);
              g.addColorStop(0, isBlack ? blackStartColor : whiteStartColor);
              g.addColorStop(1, isBlack ? blackEndColor : whiteEndColor);
              context.fillStyle = g;
              context.fill();
            }
          });
        });

        context.beginPath();
        context.arc(curX, curY, 20, 0, ROUND);
        context.closePath();

        context.shadowBlur = 0;
        context.shadowOffsetX = 0;
        context.shadowOffsetY = 0;
        // context.fillStyle = "rgba(0,175,255,.5)";
        // context.fill();
        context.setLineDash([4, 4]);
        context.strokeStyle = "skyblue";
        context.stroke();

        requestAnimationFrame(render);
      }
      render();
    </script>
  </body>
</html>
